package 扩展类

import (
	"bytes"
	"golang.org/x/text/encoding/simplifiedchinese"
	"os/exec"
	"runtime"
	"time"
	"unicode/utf8"
)

// X延时 是一个函数，用于在程序中插入一个指定长度的毫秒级暂停。
// 这个函数接受一个整数参数 毫秒，表示需要暂停的时间长度。
// 通过将 毫秒 转换为 time.Duration 类型，并乘以 time.Millisecond，
// 函数能够实现精确的毫秒级延时，这对于需要精确时间控制的场景非常有用。
func X延时(毫秒 int) {
	time.Sleep(time.Duration(毫秒) * time.Millisecond)
}

// X是否为Win 检查当前操作系统是否为 Windows。
// 在线测试: https://go.dev/play/p/XzJULbzmf9m
func X是否为Win() bool {
	return runtime.GOOS == "windows"
}

// X是否为Linux 检查当前操作系统是否为Linux。
// 示例：https://go.dev/play/p/zIflQgZNuxD
func X是否为Linux() bool {
	return runtime.GOOS == "linux"
}

// X是否为MacOS 检查当前操作系统是否为macOS。
// 示例：https://go.dev/play/p/Mg4Hjtyq7Zc
func X是否为MacOS() bool {
	return runtime.GOOS == "darwin"
}

// X取操作系统位数 返回当前操作系统的位数（32或64位）。
// 示例：https://go.dev/play/p/ml-_XH3gJbW
func X是否为64位系统() bool {
	if 32<<(^uint(0)>>63) == 64 {
		return true
	}
	return false
}

// X是否为32位系统 判断当前系统是否为32位。
// 该函数通过位操作来检测系统的位数。
// 返回值: 如果系统是32位，则返回true；如果是64位，则返回false。
func X是否为32位系统() bool {
	// 使用位移操作来检测系统位数。
	// ^uint(0) 产生一个所有位都取反的无符号整数。
	// >>63 将该数右移63位，如果系统是32位的，那么这个操作的结果是0；
	// 如果是64位的，结果是1。因为32位系统中，没有第63位，所以右移63位后为0。
	// 32<< 将32左移上述结果位数。如果系统是32位，左移0位，结果还是32；
	// 如果是64位，左移1位，结果是64。
	// 因此，如果表达式的结果是32，说明系统是32位的。
	if 32<<(^uint(0)>>63) == 32 {
		return true
	}
	return false
}

// 运行命令，返回命令的stdout和stderr字符串，并在出现错误时返回错误信息
// 参数`command`是一个完整的命令字符串，例如，在linux下为'ls -a'，在windows下为'dir'或者'ping 127.0.0.1'
// 在linux环境下，使用/bin/bash -c 来执行命令
// 在windows环境下，使用powershell.exe来执行命令
// 示例：https://go.dev/play/p/n-2fLyZef-4
func X运行命令(命令 string, 选项 ...func(*exec.Cmd)) (标准输出, 标准错误输出 string, 错误 error) {
	var out bytes.Buffer
	var errOut bytes.Buffer

	cmd := exec.Command("/bin/bash", "-c", 命令)
	if X是否为Win() {
		cmd = exec.Command("powershell.exe", 命令)
	}

	for _, opt := range 选项 {
		if opt != nil {
			opt(cmd)
		}
	}
	cmd.Stdout = &out
	cmd.Stderr = &errOut

	错误 = cmd.Run()

	if 错误 != nil {
		if utf8.Valid(errOut.Bytes()) {
			标准错误输出 = byteToString(errOut.Bytes(), "UTF8")
		} else if X编码是否为gbk(errOut.Bytes()) {
			标准错误输出 = byteToString(errOut.Bytes(), "GBK")
		}
		return
	}

	data := out.Bytes()
	if utf8.Valid(data) {
		标准输出 = byteToString(data, "UTF8")
	} else if X编码是否为gbk(data) {
		标准输出 = byteToString(data, "GBK")
	}

	return
}

func byteToString(data []byte, charset string) string {
	var result string

	switch charset {
	case "GBK":
		decodeBytes, _ := simplifiedchinese.GBK.NewDecoder().Bytes(data)
		result = string(decodeBytes)
	case "GB18030":
		decodeBytes, _ := simplifiedchinese.GB18030.NewDecoder().Bytes(data)
		result = string(decodeBytes)
	case "UTF8":
		fallthrough
	default:
		result = string(data)
	}

	return result
}
